﻿using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;

using RpcClient.Config;
using RpcClient.Helper;
using RpcClient.Interface;
using RpcClient.Model;
using RpcClient.RouteDelegate;

using RpcModel;

namespace RpcClient.Collect
{
    [Attr.ClassLifetimeAttr(Attr.ClassLifetimeType.单例)]
    internal class TcpRouteCollect : ITcpRouteCollect
    {
        static TcpRouteCollect()
        {
            RpcMsgCollect.SetMsgEvent(_RemoteMsgEvent);
            RpcQueueCollect.SetMsgEvent(_QueueMsgEvent);
        }



        private static readonly ConcurrentDictionary<string, IRoute> _RouteList = new ConcurrentDictionary<string, IRoute>();

        public event Action<IRoute> RegRouteEvent;

        public void AddRoute(IRoute route)
        {
            if (_RouteList.TryAdd(route.RouteName, route) && RegRouteEvent != null)
            {
                RegRouteEvent(route);
            }
        }

        public void RemoveRoute(string name)
        {
            if (_RouteList.ContainsKey(name))
            {
                _RouteList.TryRemove(name, out _);
            }
        }
        public bool CheckIsExists(string route)
        {
            return _RouteList.ContainsKey(route);
        }

        public void Dispose()
        {
            _RouteList.Clear();
        }
        #region 添加路由


        public void AddRoute<T>(string name, RpcFunc<T> action)
        {
            this._AddRoute<T>(name, action);
        }
        public void AddRoute<T, Result>(string name, RpcFunc<T, Result> action)
        {
            this._AddRoute<T>(name, action);
        }
        public void AddRoute<T, Result>(string name, RpcFuncSource<T, Result> action)
        {
            this._AddRoute<T>(name, action);
        }
        public void AddRoute<T>(string name, RpcActionSource<T> action)
        {
            this._AddRoute<T>(name, action);
        }

        public void AddRoute(string name, RpcAction action)
        {
            this._AddRoute(name, action);
        }
        public void AddRoute<T>(string name, RpcAction<T> action)
        {
            this._AddRoute<T>(name, action);
        }
     
        public void AddRoute<T>(RpcAction<T> action)
        {
            this._AddRoute<T>(typeof(T).Name, action);
        }

        public void AddRoute<T>(RpcFunc<T> action)
        {
            this._AddRoute<T>(typeof(T).Name, action);
        }

      
        #endregion


        #region 私有方法
        private ITcpRoute _CreateDelegate(string name, Delegate source, string show)
        {
            MethodInfo method = source.Method;
            if (method.ReturnType == ConfigDic.VoidType)
            {
                return new VoidFuncDelegate(name, source, show);
            }
            else if (method.ReturnType == ConfigDic.ReturnType)
            {
                return new BasicRouteDelegate(name, source, show);
            }
            else
            {
                return new ReturnFuncDelegate(name, source, show);
            }
        }
        private void _AddRoute(string name, Delegate source)
        {
            if (_RouteList.ContainsKey(name))
            {
                return;
            }
            ITcpRoute route = this._CreateDelegate(name, source, null);
            this.AddRoute(route);
        }
        private void _AddRoute<T>(string name, Delegate source)
        {
            if (_RouteList.ContainsKey(name))
            {
                return;
            }
            string show = XmlShowHelper.FindShow(typeof(T));
            ITcpRoute route = this._CreateDelegate(name, source, show);
            this.AddRoute(route);
        }
        private static IBasicRes _MsgEvent(IRoute route, IMsg msg)
        {
            return route.TcpMsgEvent(msg);
        }
        private static IBasicRes _QueueMsgEvent(IMsg msg)
        {
            if (_RouteList.TryGetValue(msg.MsgKey, out IRoute route))
            {
                return _MsgEvent(route, msg);
            }
            return null;
        }
        private static IBasicRes _RemoteMsgEvent(IMsg msg)
        {
            if (_RouteList.TryGetValue(msg.MsgKey, out IRoute route))
            {
                return _MsgEvent(route, msg);
            }
            return new BasicRes("rpc.route.no.find");
        }

        public IRoute[] GetRoutes()
        {
            return _RouteList.Values.ToArray();
        }


        #endregion

    }
}